

#ifndef rpcclient_h__
#define rpcclient_h__

#include <exception>
#include "services.h"
#include <boost/foreach.hpp>


namespace rpc {

class server
{
public:
  server() {}
  ~server(){}

  void register_service(rpc::services::iservice* s) {
    int channel_id = services_.size();
    services_[channel_id] = s;
  }

  void handle_message(
    rpc::protocol::message& input_msg, 
    rpc::protocol::message& output_msg, 
    rpc::connection_ptr s) 
  {
    output_msg.channel = input_msg.channel;
    int type = input_msg.type;
    switch(type) {
    case rpc::protocol::message_request:
      handle_request(input_msg, output_msg, s);
      break;
  
    case rpc::protocol::message_event:
      handle_event(input_msg, output_msg, s);
      break;
    default:
      {
        rpc::protocol::response res;
        res.put_result_code(-2);
        res.body().put("message", "unacceptable methods");
        res.to_string(output_msg.body);
      }
    } 
  }

private:
  // handle normal request
  void handle_request(
    rpc::protocol::message& input_msg, 
    rpc::protocol::message& output_msg, 
    rpc::connection_ptr s) 
  {
    rpc::protocol::request req(input_msg.body);
    rpc::protocol::response res;
    // serialize from request
    try {
      if(input_msg.channel < 0) {
        // server message
      } else {
        // get service object
        rpc::services::iservice* is = get_service(input_msg.channel);
        if(!is) { // error occurred
          std::ostringstream oss;
          oss << "unknow service id:" << input_msg.channel;
          throw rpc::exception(oss.str().c_str());						
        }
				
        // service process 
        is->process(req, res, s);
      }
    }
    catch (const std::exception& e) {
      res.put_result_code(-1);
      res.body().put("message", e.what());
    }

    output_msg.channel = input_msg.channel;
    // serialize to response		
    res.to_string(output_msg.body);
  }

  void handle_event(
    rpc::protocol::message& input_msg, 
    rpc::protocol::message& output_msg, 
    rpc::connection_ptr s) 
  {
      //rpc::services::iservice* is = get_service(input_msg.channel);
      //if(!is) { // error occurred
      //    std::ostringstream oss;
      //    oss << "unknow service id:" << input_msg.channel;
      //    throw rpc::exception(oss.str().c_str());						
      // }
  }

public:
  rpc::services::iservice* get_service(int channel) {
    std::map<int, rpc::services::iservice*>::const_iterator c = services_.find(channel);
    if(c != services_.end())
      	return c->second;

    return 0;
  }

  void dump_services_info(std::string& json_data) {
    boost::property_tree::ptree tree;
    tree.put("action", "serviceinfo");
    boost::property_tree::ptree array;
    std::map<int, rpc::services::iservice*>::const_iterator c = services_.begin();
    while(c != services_.end()) {
      boost::property_tree::ptree s;
      s.put("id", c->first);
      s.put("name", c->second->name());

      boost::property_tree::ptree func_array;
      std::map<int, std::string> funcs_map;
      c->second->register_functions(funcs_map);
      std::map<int, std::string>::const_iterator f = funcs_map.begin();
      while(f!=funcs_map.end()) {
        boost::property_tree::ptree func_item;
        func_item.put("id", f->first);
        func_item.put("name", f->second);
        func_array.push_back(std::make_pair("", func_item));
        f++;
      }

      s.put_child("funcs", func_array);
      array.push_back(std::make_pair("", s)); 
      c++;
    }

    tree.put_child("services", array);

    std::ostringstream out_stream;
    boost::property_tree::json_parser::write_json(out_stream, tree);
    json_data = out_stream.str();
  }

private: 
  std::map<int, rpc::services::iservice*> services_;
};

} // namespace rpc


#endif

